<?php

// +----------------------------------------------------------------------
// | 版权所有 2017-2027 云南环拓科技有限公司，并保留所有权利。
// +----------------------------------------------------------------------
// | Copyright (c) 2017-2027 http://www.yn123.com All rights reserved.
// +----------------------------------------------------------------------
// | Notice: This code is not open source, it is strictly prohibited
// |         to distribute the copy, otherwise it will pursue its
// |         legal responsibility.
// | 注意：  这不是一个自由软件！您只能在不用于商业目的的前提下对程序代码进行修改和使用,
// |        不允许对程序代码以任何形式任何目的的再发布。
// +----------------------------------------------------------------------
// | Author: feraner <feraner@163.com> 
// | Date: 2019/11/6
// +----------------------------------------------------------------------

namespace app\common\services;
use app\common\constants\ApiConstant;
use app\common\facade\Arr;
use app\common\facade\Help;
use app\common\facade\TransItem;
use app\common\services\wechattemplate\JobTemplateService;
use library\tools\Data;
use think\Db;

/**
 * 兼职服务类
 * Class JobService
 * @package app\common\services
 * @author feraner<feraner@163.com>
 * @date 2019/11/6
 */
class PublishJobService
{


    /**
     * 发布兼职
     * @param $postData
     *
     * @return bool|mixed
     * @throws \Exception
     */
    public function publishJob($postData)
    {
        $result = false;
        try {
            Db::startTrans();
            $checkPostData = $this->__beforePublishJob($postData);
            if ($checkPostData) {
                $handlePostData = $this->__publishJobHandle($checkPostData);
                if ($handlePostData) {
                    $result = $this->__afterPublishJob($handlePostData);
                    Db::commit();
                }
            }
        } catch (\Exception $e) {
            Db::rollback();
            throw $e;
        }
        return $result;
    }


    /**
     * 兼职发布前需要检测是否可以发布兼职
     *
     * @param $postData
     *
     * @return mixed
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\ModelNotFoundException
     * @throws \think\exception\DbException
     * @throws \Exception
     */
    private function __beforePublishJob($postData)
    {

        //before 地区转换
        $this->__converLocationToArea($postData);

        //如果是后台发布，不需要检测
        if (!Arr::get($postData, 'admin_id')) {
            //1: 检测用户是否可以发布,发布前需完善个人信息
            $userInfo = (new UserService())->userInfo(Arr::get($postData, 'user_id'));
            if (!(new UserService())->checkUserInfoIsDone($userInfo)) {
                throw  new \Exception(
                    ApiConstant::USER_INFO_NOT_DONE_STR,
                    ApiConstant::USER_INFO_NOT_DONE
                );
            }

            //2: 检测用户是否有足够发布豆
            $needBean = (new PublishJobComputerService())->needBean($postData);
            $userWallet = Db::name('user_wallet')
                ->where('user_id', Arr::get($userInfo, 'id'))
                ->find() ?: [];
            if (Arr::get($userWallet, 'publish_bean') < Arr::get($needBean, 'needBean')) {
                throw new \Exception(
                    ApiConstant::JOB_PUBLISH_NOT_ENOUGH_BEAN_STR,
                    ApiConstant::JOB_PUBLISH_NOT_ENOUGH_BEAN
                );
            }
            $postData['needBean'] = $needBean;
            $postData['need_bean'] = Arr::get($needBean, 'needBean', 0);
            $postData['give_credits'] = Arr::get($needBean, 'giveCredits', 0);

            //3: 查看用户是否是商家
            $companyInfo = Db::name('user_extend_bus')
                ->where('user_id', Arr::get($userInfo, 'id'))
                ->field('id,user_id,company_name')
                ->find() ?: [];
            if ($companyInfo) {
                $postData['business_id'] = Arr::get($companyInfo, 'user_id', 0);
            }



        } else {
            //后台发布，不需要审核
            $postData['status'] = 2;
            $postData['publish_at'] = time();
        }


        return $postData;
    }


    /**
     * 添加兼职到数据库
     * postData 添加两个参数
     *      一个是  id : 兼职ID
     *      一个是 contentId : 兼职扩展表ID
     * @param $postData
     *
     * @throws \think\Exception
     * @throws \think\exception\PDOException
     */
    private function __publishJobHandle($postData)
    {
        $locationArr = $this->__getLatitudeAndLongitude($postData);


        $jobInsertData = $this->__getJobsInsertData($postData, $locationArr);

        if ($jobId = Arr::get($postData, 'id')) {
            $jobInsertData['id'] = $jobId;
        }
        $jobInsertId = Data::save('jobs', $jobInsertData);
        if ($jobInsertId) {
            $jobExtendData = [
                'job_id'    => $jobId ?: $jobInsertId,
                'content'   => Arr::get($postData, 'content'),
                'requirement' => Arr::get($postData, 'requirement'),
                'work_welfare'=> Arr::get($postData, 'work_welfare'),
            ];
            if ($extendId = Arr::get($postData, 'extendId')) {
                $jobExtendData['id'] = $extendId;
            }
            $jobExtendId = Data::save('jobs_content', $jobExtendData);
            if ($jobExtendId) {
                return array_merge(
                    $postData,
                    [
                        'id'        => $jobId ?: $jobInsertId,
                        'contentId'  => $extendId ?: $jobExtendId
                    ]
                );
            }
            new \Exception('jobs_content');
        }
        new \Exception('jobs insert error');
    }


    /**
     * 发布兼职成功后的事项处理
     * @param $postData
     *
     * @return mixed
     * @throws \WeChat\Exceptions\InvalidResponseException
     * @throws \WeChat\Exceptions\LocalCacheException
     * @throws \think\Exception
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\ModelNotFoundException
     * @throws \think\exception\DbException
     * @throws \think\exception\PDOException
     */
    private function __afterPublishJob($postData)
    {
        
        if (Arr::get($postData, 'admin_id')) {
            //后台管理人员发布，无需审核
            //1：更新该类型的兼职发布数
            Db::name('jobs_type')
                ->where('id', Arr::get($postData, 'work_type', 0))
                ->setInc('job_num');

            //2: 更新该用户发布的兼职数
            Db::name('user_extend')
                ->where('user_id', Arr::get($postData, 'user_id', 0))
                ->setInc('publish_job_num');
        } else {
            //普通用户发布
            
            //1: 锁定需要的发布豆
            Db::name('user_wallet')
                ->where('user_id', Arr::get($postData, 'user_id'))
                ->update([
                    'publish_bean'  => Db::raw('publish_bean - ' . Arr::get($postData['needBean'], 'needBean', 0)),
                    'clock_publish_bean' => Db::raw('clock_publish_bean + ' . Arr::get($postData['needBean'], 'needBean', 0)),
                    'clock_credits' => Db::raw('clock_credits + ' . Arr::get($postData['needBean'], 'giveCredits', 0)),
                    'updated_at'    => time()
                ]);

            //2:通知管理人员审核, 基于微信模版消息 手机微信审核
            $result = (new JobTemplateService())->sendAuditJob($postData);
        }

        return $postData;
    }


    /**
     * 审核同意用户发布到兼职
     * @param $jobId
     *
     * @throws \think\Exception
     */
    public function approvedJob($jobId, $userId)
    {
        $jobInfo = Db::name('jobs')
            ->where('id', $jobId)
            ->where('status', 'IN', [1, 3])
            ->find() ?: [];
        if ($jobId && $jobInfo) {
            try {
                Db::startTrans();
                //1：更新该类型的兼职发布数
                Db::name('jobs_type')
                    ->where('id', Arr::get($jobInfo, 'work_type', 0))
                    ->setInc('job_num');

                //2: 更新该用户发布的兼职数
                Db::name('user_extend')
                    ->where('user_id', Arr::get($jobInfo, 'user_id', 0))
                    ->setInc('publish_job_num');

                //3: 积分和发布豆
                $needBean = (new PublishJobComputerService())->needBean($jobInfo);
                Db::name('user_wallet')
                    ->where('user_id', Arr::get($jobInfo, 'user_id'))
                    ->update([
                        'used_publish_bean'  => Db::raw('used_publish_bean + ' . Arr::get($needBean, 'baseBean')),
                        'clock_publish_bean' => Db::raw('clock_publish_bean - ' . Arr::get($needBean, 'baseBean')),
                        'clock_credits' => Db::raw('clock_credits - ' . Arr::get($needBean, 'baseGiveCredits')),
                        'credits'       => Db::raw('credits + ' . Arr::get($needBean, 'baseGiveCredits')),
                        'updated_at'    => time()
                    ]);

                //4: 发布豆 + 积分 log记录
                if (Arr::get($needBean, 'baseBean', 0)) {
                    Db::name('user_recharge_log')
                        ->insertGetId([
                            'user_id'           => Arr::get($jobInfo, 'user_id'),
                            'recharge_money'    => 0,
                            'type'              => 2,
                            'publish_bean'      => Arr::get($needBean, 'baseBean'),
                            'kind'              => 1,
                            'created_at'        => time(),
                            'updated_at'        => time()
                        ]);
                }
                if (Arr::get($needBean, 'baseGiveCredits', 0)) {
                    Db::name('user_credits_log')
                        ->insertGetId([
                            'user_id'           => Arr::get($jobInfo, 'user_id'),
                            'credits'           => Arr::get($needBean, 'baseGiveCredits', 0),
                            'type'              => 1,
                            'kind'              => 1,
                            'created_at'        => time(),
                            'updated_at'        => time()
                        ]);
                }

                
                //5: 修改兼职状态
                Db::name('jobs')
                    ->where('id', Arr::get($jobInfo, 'id', 0))
                    ->update([
                        'status'        => 2,
                        'publish_at'    => time(),
                        'audit_user_id' => $userId,
                        'updated_at'    => time()
                    ]);

                //6: 通知用户发布的兼职审核成功
                (new JobTemplateService())->sendAuditJobSuccess($jobInfo);
                
                

                Db::commit();
                return true;
            } catch (\Exception $e) {
                Db::rollback();
            }
        }
        return false;
    }


    /**
     * 审核不通过 -- 用户发布的兼职
     * @param $jobId
     * @param $message
     *
     * @return bool
     * @throws \think\Exception
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\ModelNotFoundException
     * @throws \think\exception\DbException
     * @throws \think\exception\PDOException
     */
    public function rejectJob($jobId, $userId, $message)
    {
        $jobInfo = Db::name('jobs')
            ->where('id', $jobId)
            ->where('status', 'IN', [1, 3])
            ->find() ?: [];

        if ($jobInfo) {
            try {
                Db::startTrans();
                //1: 发布豆 + 积分处理
                $needBean = (new PublishJobComputerService())->needBean($jobInfo);
                Db::name('user_wallet')
                    ->where('user_id', Arr::get($jobInfo, 'user_id'))
                    ->update([
                        'publish_bean'  => Db::raw('publish_bean + ' . Arr::get($needBean, 'needBean')),
                        'clock_publish_bean' => Db::raw('clock_publish_bean - ' . Arr::get($needBean, 'needBean')),
                        'clock_credits' => Db::raw('clock_credits - ' . Arr::get($needBean, 'giveCredits')),
                        'updated_at'    => time()
                    ]);

                //2: 修改兼职状态
                Db::name('jobs')
                    ->where('id', Arr::get($jobInfo, 'id', 0))
                    ->update([
                        'status'        => 3,
                        'audit_message' => $message,
                        'audit_user_id' => $userId,
                        'updated_at'    => time()
                    ]);

                //3: 通知用户发布的兼职审核失败
                (new JobTemplateService())->sendAuditJobFalse($jobInfo, $message);

                Db::commit();
                return true;
            } catch (\Exception $e) {
                Db::rollback();
            }
        }
        return false;
    }








    /**
     * 兼职保存为草稿
     * @param $postData
     *
     * @return bool
     */
    public function saveJobDraft($postData)
    {
        $result = false;
        try {
            Db::startTrans();
            $locationArr = $this->__getLatitudeAndLongitude($postData);
            $this->__converLocationToArea($postData);

            $jobInsertData = $this->__getJobsInsertData($postData, $locationArr);

            if ($jobId = Arr::get($postData, 'id')) {
                $jobInsertData['id'] = $jobId;
            }
            $jobInsertId = Data::save('jobs', $jobInsertData);
            if ($jobInsertId) {
                $jobExtendData = [
                    'job_id'    => $jobId ?: $jobInsertId,
                    'content'   => Arr::get($postData, 'content'),
                    'requirement' => Arr::get($postData, 'requirement'),
                    'work_welfare'=> Arr::get($postData, 'work_welfare'),
                ];
                if ($extendId = Arr::get($postData, 'extendId')) {
                    $jobExtendData['id'] = $extendId;
                }
                $jobExtendId = Data::save('jobs_content', $jobExtendData);
                if ($jobExtendId) {
                    $result = [
                        'jobId'         => Arr::get($jobExtendData, 'job_id', 0),
                        'extendId'      => $extendId ?: $jobExtendId
                    ];
                    Db::commit();
                } else {
                    throw new \Exception(
                        ApiConstant::JOB_PUBLISH_INSERT_JOBS_CONTENT_ERR_STR,
                        ApiConstant::JOB_PUBLISH_INSERT_JOBS_CONTENT_ERR
                    );
                }
            } else {
                throw new \Exception(
                    ApiConstant::JOB_PUBLISH_INSERT_JOBS_ERR_STR,
                    ApiConstant::JOB_PUBLISH_INSERT_JOBS_ERR
                );
            }
        } catch (\Exception $e) {
            Db::rollback();
        }
        return $result;
    }


    /**
     * 地址转成获取到系统中的地址ID
     * @param $postData
     */
    private function __converLocationToArea(&$postData)
    {
        $location = array_values(array_filter(explode(' ', trim(Arr::get($postData, 'provinces_name')))));
        $provincesId = Db::name('area')
            ->where('area_name', 'LIKE', '%' . Arr::get($location, 0) . '%')
            ->where('area_deep', 1)
            ->value('area_id') ?: 0;
        $cityId = Db::name('area')
            ->where('area_name', 'LIKE', '%' . Arr::get($location, 1) . '%')
            ->where('area_deep', 2)
            ->value('area_id') ?: 0;
        $countyId = Db::name('area')
            ->where('area_name', 'LIKE', '%' . Arr::get($location, 2) . '%')
            ->where('area_deep', 3)
            ->value('area_id') ?: 0;

        $postData['provincesId'] = $provincesId;
        $postData['cityId'] = $cityId;
        $postData['countyId'] = $countyId;
        $postData['provinces_id'] = $provincesId;
        $postData['city_id'] = $cityId;
        $postData['county_id'] = $countyId;
    }



    /**
     * 地址转换成经纬度
     * @param $postData
     *
     * @return array
     */
    private function __getLatitudeAndLongitude($postData)
    {
        $city = array_values(array_filter(explode(' ', Arr::get($postData, 'provinces_name'))));
        $location = Help::addressToLatLng(
            Arr::get($postData, 'provinces_name') . Arr::get($postData, 'address'),
            Arr::get($city, 1)
        );
        return $location;
    }


    /**
     * jobs 表需要插入到数据
     * @param $postData
     * @param $locationToArea
     * @param $locationArr
     *
     * @return array
     */
    private function __getJobsInsertData($postData, $locationArr)
    {
        $insertData = [
            'user_id'       => Arr::get($postData, 'user_id'),
            'status'        => Arr::get($postData, 'status'),
            'business_id'   => Arr::get($postData, 'business_id', 0),
            'admin_id'      => Arr::get($postData, 'admin_id', 0),
            'title'         => Arr::get($postData, 'title'),
            'work_type'     => Arr::get($postData, 'work_type'),
            'contacts'      => Arr::get($postData, 'contacts'),
            'mobile'        => Arr::get($postData, 'mobile'),
            'work_time'     => Arr::get($postData, 'work_time'),
            'work_time_end' => Arr::get($postData, 'work_time_end'),
            'work_up_time'  => Arr::get($postData, 'work_up_time', ''),
            'work_down_time'=> Arr::get($postData, 'work_down_time', ''),
            'provinces_id'  => Arr::get($postData, 'provincesId', 0),
            'city_id'       => Arr::get($postData, 'cityId', 0),
            'county_id'     => Arr::get($postData, 'countyId', 0),
            'address'       => Arr::get($postData, 'address'),
            'provinces_name'=> Arr::get($postData, 'provinces_name'),
            'salary'        => Arr::get($postData, 'salary'),
            'salary_unit'   => Arr::get($postData, 'salary_unit'),
            'need_worker'   => Arr::get($postData, 'need_worker'),
            'settlement_type'=> Arr::get($postData, 'settlement_type', 0),
            'created_at'    => time(),
            'updated_at'    => time(),
            'longitude'     => Arr::get($locationArr, 'lng'),
            'latitude'      => Arr::get($locationArr, 'lat'),
            'is_recommend'  => Arr::get($postData, 'is_recommend', 0),
            'gender'        => Arr::get($postData, 'gender', 0),
            'is_top'        => Arr::get($postData, 'is_top', 0),
            'click_num'     => Arr::get($postData, 'click_num', 0),
            'share_num'     => Arr::get($postData, 'share_num', 0),
            'collect_num'   => Arr::get($postData, 'collect_num', 0),
            'need_bean'     => Arr::get($postData, 'need_bean', 0),
            'give_credits'  => Arr::get($postData, 'give_credits', 0)
        ];

        return $insertData;
    }


}
